package com.yindian.cos.easy.security.authentication.verify;

import com.yindian.cos.easy.security.exception.AuthenticationException;
import com.yindian.cos.easy.security.exception.AuthorizationErrorException;
import com.yindian.cos.easy.security.exception.NullAuthorizationException;
import com.yindian.cos.easy.security.properties.BasicAuthProperties;
import com.yindian.cos.easy.security.properties.ClientProperties;
import com.yindian.cos.easy.security.properties.EasySecurityProperties;
import com.yindian.cos.easy.security.properties.TokenVerifyProperties;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Base64;
import java.util.Map;
import java.util.Set;

/**
 * basic auth 验证，验证头中是否包含根据clients配置生成的Authorization
 * header中key为Authorization
 * value生成规则为: Basic + Base64.encode(clientId:clientSecret),例如 Basic dGVzdDp0ZXN0
 *
 * @author zhangchuanhao
 * @create 2018/11/22
 * @see ClientProperties
 */
@Log4j2
public class BasicAuthVerifyAuthentication extends AbstractVerifyAuthentication {

    private final EasySecurityProperties easySecurityProperties;

    private final static String basic = "Basic ";

    private final static String authorizationKey = "Authorization ";

    public BasicAuthVerifyAuthentication(EasySecurityProperties easySecurityProperties) {
        this.easySecurityProperties = easySecurityProperties;
    }

    @Override
    public void verify(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        TokenVerifyProperties tokenVerifyProperties = easySecurityProperties.getTokenVerify();
        String[] exclusions = tokenVerifyProperties.getExclusions();
        if (!interceptOrPass(exclusions, request.getRequestURI())) {
            log.debug("执行拦截过滤器{}", this.getClass().getSimpleName());
            String authorization = request.getHeader(authorizationKey);
            if (StringUtils.isBlank(authorization)) {
                throw new NullAuthorizationException("authorization not null");
            } else {
                if (StringUtils.startsWith(authorization, basic)) {
                    authorization = StringUtils.substringAfter(authorization, basic);
                    authorization = new String(Base64.getDecoder().decode(authorization));
                    String[] client = authorization.split(":");
                    if (client == null || client.length != 2) {
                        throw new AuthorizationErrorException("authorization error");
                    }
                    Map<String, ClientProperties> clients = easySecurityProperties.getClients();
                    Set<String> keys = clients.keySet();
                    boolean flag = false;
                    for (String key : keys) {
                        ClientProperties clientProperties = clients.get(key);
                        if (clientProperties.getClientId().equals(client[0])
                                && clientProperties.getClientSecret().equals(client[1])) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        throw new AuthorizationErrorException("authorization error");
                    }
                } else {
                    throw new AuthorizationErrorException("authorization error");
                }
            }
        }
    }

    @Override
    public boolean next(HttpServletRequest request) {
        return true;
    }

    @Override
    public boolean support(HttpServletRequest request) {
        BasicAuthProperties basicAuthProperties = easySecurityProperties.getBasicAuth();
        String[] includes = basicAuthProperties.getIncludes();
        return interceptOrPass(includes, request.getRequestURI());
    }

    @Override
    public int order() {
        return easySecurityProperties.getBasicAuth().getOrder();
    }
}
